/* Copyright 2012 University of Ulm

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

package de.uulm.inki.arqtest;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import junit.framework.Test;

import com.hp.hpl.jena.query.ARQ;
import com.hp.hpl.jena.query.Syntax;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.impl.PropertyImpl;
import com.hp.hpl.jena.sparql.core.DataFormat;
import com.hp.hpl.jena.sparql.junit.QueryTest;
import com.hp.hpl.jena.sparql.junit.QueryTestException;
import com.hp.hpl.jena.sparql.junit.ScriptTestSuiteFactory;
import com.hp.hpl.jena.sparql.junit.TestItem;
import com.hp.hpl.jena.sparql.junit.TestQueryUtils;
import com.hp.hpl.jena.sparql.util.Symbol;
import com.hp.hpl.jena.sparql.vocabulary.TestManifest;
import com.hp.hpl.jena.sparql.vocabulary.TestManifestUpdate_11;
import com.hp.hpl.jena.sparql.vocabulary.TestManifestX;
import com.hp.hpl.jena.sparql.vocabulary.TestManifest_11;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.util.junit.TestUtils;
import com.hp.hpl.jena.vocabulary.RDF;

public class InferenceScriptTestSuitFactory extends ScriptTestSuiteFactory {
    
    public static final String SD="http://www.w3.org/ns/sparql-service-description#";
    
    protected FileManager fileManager=FileManager.get();
    protected final Set<String> allowedRegimes;
    protected final Set<String> includeOnlyTests;
    
    public InferenceScriptTestSuitFactory() {
        allowedRegimes=new HashSet<String>(Arrays.asList(TestRunner.includeOnlySemantics));
        includeOnlyTests=new HashSet<String>(Arrays.asList(TestRunner.includeOnlyTests));
    }
    
    @Override
    public Test makeTest(Resource manifest,Resource entry,String testName,Resource action,Resource result) {
        boolean includeTest=true;
        if (!includeOnlyTests.isEmpty()) {
            includeTest=false;
            for (String allowedTestName : includeOnlyTests)
                if (testName.startsWith(allowedTestName)) {
                    includeTest=true;
                    break;
                }
        }
        if (includeTest) {
            if (action==null) {
                System.out.println("Null action: "+entry);
                return null;
            } 
            // Defaults
            Syntax querySyntax=TestQueryUtils.getQuerySyntax(manifest);
            if (querySyntax!=null && !querySyntax.equals(Syntax.syntaxARQ) && !querySyntax.equals(Syntax.syntaxSPARQL_10) && !querySyntax.equals(Syntax.syntaxSPARQL_11))
                throw new QueryTestException("Unknown syntax: "+querySyntax);
            // May be null
            Resource defaultTestType=TestUtils.getResource(manifest,TestManifestX.defaultTestType);
            // test name,test type,action -> query specific query[+data],results
            Resource testType=defaultTestType;
            if (entry.hasProperty(RDF.type))
                testType=entry.getProperty(RDF.type).getResource();
            TestItem item=null;
            if (testType==null || (!testType.equals(TestManifestUpdate_11.UpdateEvaluationTest) && !testType.equals(TestManifest_11.UpdateEvaluationTest))) 
                item=TestItem.create(entry,defaultTestType,querySyntax,DataFormat.langXML);
            if (testType!=null && (testType.equals(TestManifest.QueryEvaluationTest) || testType.equals(TestManifestX.TestQuery))) {
                Property sd_entailmentRegime=new PropertyImpl(SD, "entailmentRegime");
                boolean isRelevantTest=false;
                if (action.hasProperty(sd_entailmentRegime)) {
                    Resource regime=TestUtils.getResource(action, sd_entailmentRegime);
                    if (regime.isResource() && allowedRegimes.contains(regime.toString())) {
                        isRelevantTest=true;
                        ARQ.getContext().set(Symbol.create("Semantics"), regime.toString());
                    } else if (regime.isAnon() && regime.getProperty(RDF.first)!=null) {
                        Resource listItem=regime;
                        Set<String> suitableRegimes=new HashSet<String>();
                        while (!listItem.equals(RDF.nil)&&!isRelevantTest) {
                            regime=listItem.getProperty(RDF.first).getResource();
                            if (regime.isResource() && allowedRegimes.contains(regime.toString())) {
                                isRelevantTest=true;
                                suitableRegimes.add(regime.toString());
                            } 
                            listItem=listItem.getProperty(RDF.rest).getResource();
                        }
                        if (suitableRegimes.contains(TestRunner.RDFS_NS) || suitableRegimes.contains(TestRunner.D_NS))
                            ARQ.getContext().set(Symbol.create("Semantics"), TestRunner.RDFS_NS);
                        else if (!suitableRegimes.isEmpty()) {
                            ARQ.getContext().set(Symbol.create("Semantics"), suitableRegimes.iterator().next());
                        }
                    }
                    if (isRelevantTest)
                        return new QueryTest(testName,results,fileManager,item);
                }
            }
        }
        return null;
    }

}
